use axum::{extract::State, Json};
use jsonwebtoken as jwt;
use sqlx::{Pool, Sqlite};

use crate::{api::jwt::Claims, db::User};

use super::{jwt::{AuthError, KEYS}, ApiError};


#[derive(serde::Deserialize)]
pub struct LoginPayload {
    code: String,
}

#[derive(serde::Serialize)]
pub struct AuthBody {
    access_token: String,
    token_type: String,
}

impl AuthBody {
    pub fn new(access_token: String) -> Self {
        AuthBody {
            access_token,
            token_type: "Bearer".to_string(),
        }
    }
}


pub async fn login(
    State(pool):State<Pool<Sqlite>>,
    Json(payload):Json<LoginPayload>,
) -> Result<Json<AuthBody>, ApiError> {

    let wx_user = wx_login(payload.code).await?;

    let user = sqlx::query_as::<_, User>("select * from users where openid = ?")
        .bind(&wx_user.openid)  //bind用于将参数值绑定到SQL查询或命令中的占位符（?）上。
        .fetch_one(&pool).await;  //fetch_one用于执行一个查询，并尝试从结果集中检索单个行。

    let user = match user {
        Ok(user) => user,
        Err(sqlx::Error::RowNotFound) => { //新用户
            sqlx::query("insert into users (openid, session_key) values (?, ?)")
                .bind(&wx_user.openid)
                .bind(&wx_user.session_key)
                .execute(&pool).await?; //.execute方法用于执行一个不返回结果集的SQL命令（如INSERT、UPDATE或DELETE语句）, 返回一个表示受该命令影响的行数

            sqlx::query_as::<_, User>("select * from users where openid = ?")
                .bind(&wx_user.openid)
                .fetch_one(&pool).await?
        },
        Err(e) => return Err(e.into()),
    };

    let claims = Claims::new(user.id.to_string().to_string());
    let token = jwt::encode(
        &jwt::Header::default(), &claims, 
           &KEYS.encoding,
    ).map_err(|_| AuthError::TokenCreation)?;

    Ok(Json(AuthBody::new(token)))
}


#[derive(serde::Deserialize, Default)]
struct WxUser {
    pub openid: String,
    pub session_key: String,
}

async fn wx_login(code: String) -> Result<WxUser, AuthError> {
    // if code.is_empty() {
    //     return Err(AuthError::MissingCredentials)
    // }

    // let app_id = std::env::var("APP_ID").unwrap();
    // let app_secret = std::env::var("APP_SECRET").unwrap();
    // let endpoint = format!("https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization", app_id, app_secret, code);

    // let resp = reqwest::get(endpoint)
    //     .await
    //     .map_err(|_| AuthError::WrongCredentials)?
    //     .json::<serde_json::Value>()
    //     .await
    //     .map_err(|_| AuthError::WrongCredentials)?;

    // info!("wx_login code:{}, resp:{}", code, resp);

    // let wx_user = serde_json::from_value::<WxUser>(resp).map_err(|_| AuthError::WrongCredentials)?;

    // if wx_user.openid.is_empty() {
    //     return Err(AuthError::WrongCredentials)
    // }

    // Ok(wx_user)

    Ok(WxUser{ openid: "2".to_string(), session_key: "lalala".to_string() })

}

